package CelestialWorkflow;

import CelestialDataAccess.*;
import CelestialDataStructures.*;

import java.util.Date;
import java.util.Map;
import java.util.HashMap;
import java.util.Calendar;
import java.text.ParseException;

public class AccountControl extends ValidateControl{

    /*************************************************************************/
    /* Constructors */
    public AccountControl(){}
    /*************************************************************************/
    /* Client methods */
    public Customer getCustomer(int cust_id){

        /* clear errors */
        m_mapErrors.clear();

        CustomersDataAccess daCustomers = new CustomersDataAccess();
        Customer cust;
        try{
            cust = daCustomers.getCustomerByID(cust_id);
            DataAccessBase.close();
        }catch(DataAccessException ex){
            m_mapErrors.put(SYS_ERR, "System Error: " + ex.getMessage());
            return null;
        }
        if(cust==null){
            m_mapErrors.put(EMAIL_NT_REG, "Not registered");
            return null;
        }
        return cust;
    }
    /*-----------------------------------------------------------------------*/
    public boolean registerCustomer(Map<String, String[]> param){

        /* clear errors*/
        m_mapErrors.clear();

        /* validate email */
        validateEmail(param.get("email")[0]);

        /* validate password */
        validatePassword(param.get("new_pw")[0], param.get("retype_pw")[0]);
        
        /* validate first name and last name */
        validateNames(param.get("fst_name")[0], param.get("lst_name")[0]);

        /* validate DOB */
        validateDOB((param.get("dob_yr")[0]), param.get("dob_mth")[0], param.get("dob_day")[0]);

        /* validate contact */
        validateContact(param.get("contact")[0]);

        /* validate credit card  */
        if(param.get("save_cc")[0].compareTo("yes")==0)
            validateCreditCard(param.get("cc_num")[0],
                               Integer.parseInt(param.get("cc_type")[0]),
                               param.get("cc_mth")[0], param.get("cc_yr")[0]);

        if(m_mapErrors.size() > 0) return false;

        /* if no errors from validation, proceed to populate */
        Customer cust = new Customer();
        if(!populate(cust, param, true)) return false;

        /* if no errors from population, proceed to insert */
        if(insertCustomer(cust)){
            new MailService().sendActivationLink(cust.getEmail(), cust.getFirstName());
            return true;
        } else return false;
    }
    /*-----------------------------------------------------------------------*/
    public boolean insertCustomer(Customer cust){

        try{
            new CustomersDataAccess().insertCustomer(cust);
        }catch(DataAccessException ex){
            m_mapErrors.put(SYS_ERR, "System Error: " + ex.getMessage());
            return false;
        }
        return true;
    }
    /*-----------------------------------------------------------------------*/
    public boolean updateCustomer(Map<String, String[]> param){

        /* clear errors*/
        m_mapErrors.clear();

        /* get customer first */
        CustomersDataAccess daCustomers = new CustomersDataAccess();
        Customer cust;
        try{
            int iID = Integer.parseInt(param.get("cust_id")[0]);
            cust = daCustomers.getCustomerByID(iID);
        } catch (DataAccessException ex) {
            m_mapErrors.put(SYS_ERR, "System Error: " + ex.getMessage());
            return false;
        }
        /* validate first name and last name */
        validateNames(param.get("fst_name")[0], param.get("lst_name")[0]);

        /* validate contact */
        validateContact(param.get("contact")[0]);

        /* validate email */
        validateEmail(Integer.parseInt(param.get("cust_id")[0]), param.get("email")[0]);

        /* validate credit card expiry */
        if(param.get("save_cc")[0].compareTo("yes")==0)
            validateCreditCardExpiry(param.get("cc_mth")[0], param.get("cc_yr")[0]);

        /* if errors, return */
        if(m_mapErrors.size() > 0) return false;

        /* else, proceed to populate */
        if(!populate(cust, param, false)) return false;

        /* still no errors.. proceed to update */
        return updateCustomer(cust);
    }
    /*-----------------------------------------------------------------------*/
    public boolean updateCustomer(Customer cust){

        CustomersDataAccess daCustomers = new CustomersDataAccess();
        try{
            daCustomers.updateCustomer(cust);
        }catch(DataAccessException ex){
            m_mapErrors.put(SYS_ERR, "System Error: " + ex.getMessage());
            return false;
        }
        return true;
    }
    /*-----------------------------------------------------------------------*/
    public Customer activateAccount(String email){

        m_mapErrors.clear();

        CustomersDataAccess daCustomers = new CustomersDataAccess();
        Customer cust;
        try{
            cust = daCustomers.getCustomerByEmail(email);
            if(cust==null){
                m_mapErrors.put(EMAIL_NT_REG, "Email not registered");
                return null;
            }
            else if(cust.isActive()){
                m_mapErrors.put(ACC_ACTIVATED, "Already activated");
                return null;
            }
            else{
                daCustomers.activate(email);
                return cust;
            }
        }catch(DataAccessException ex){
            m_mapErrors.put(SYS_ERR, ex.getMessage());
            return null;
        }
    }
    /*-----------------------------------------------------------------------*/
    public boolean changePassword(String pw, String pw2, int cust_id){

        /* Clear errors */
        m_mapErrors.clear();

        if(pw.length()==0){
            m_mapErrors.put(NULL_PWD, "Password required");
            return false;
        }
        if(!Validation.validatePassword(pw)){
            m_mapErrors.put(INVALID_PWD, "Invalid password");
            return false;
        }
        if(pw.compareTo(pw2)!=0){
            m_mapErrors.put(PWD_MISMATCH, "Password mismatch");
            return false;
        }
        
        /* change password */
        CustomersDataAccess daCustomers = new CustomersDataAccess();
        Customer cust;
        try{
           cust = daCustomers.getCustomerByID(cust_id);
           cust.setPassword(pw);

           daCustomers.updateCustomer(cust);
           DataAccessBase.close();
        }catch(DataAccessException ex){
            m_mapErrors.put(SYS_ERR, "System error: " + ex.getMessage());
        }
        return true;
    }
    /*-----------------------------------------------------------------------*/
    public boolean changeCreditCard(String cc_num, int cc_type, int cust_id){

        /* Clear errors */
        m_mapErrors.clear();

        if(!validateCreditCardNumber(cc_num)){
            m_mapErrors.put(AccountControl.INVALID_CC_NUM, "Invalid card");
            return false;
        }
        if(!validateCreditCardIssuer(cc_num, cc_type)){
            m_mapErrors.put(AccountControl.INVALID_CC_ISSUER, "Wrong issuer");
            return false;
        }
        /* change credit card */
        CustomersDataAccess daCustomers = new CustomersDataAccess();
        Customer cust;
        try{
           cust = daCustomers.getCustomerByID(cust_id);
           cust.setCreditCardNumber(cc_num);
           cust.setCreditCardType(cc_type);

           daCustomers.updateCustomer(cust);
        }catch(DataAccessException ex){
            m_mapErrors.put(SYS_ERR, "System error: " + ex.getMessage());
        }
        return true;
    }
    /*************************************************************************/
    /* Helpers */
    private boolean populate(Customer cust, Map<String, String[]> param, boolean insert_mode){

        /* only on registration */
        if(insert_mode){
            cust.setPassword(param.get("new_pw")[0]);
            cust.setActive(false);
            try{
            cust.setDOB(DateFormat.parse(param.get("dob_yr")[0] + "-" +
                        param.get("dob_mth")[0] + "-" +
                        param.get("dob_day")[0]));
            }catch(ParseException ex){
                m_mapErrors.put(INVALID_DOB, "Invalid date");
                return false;
            }
        }
        /* registration details */
        cust.setFirstName(param.get("fst_name")[0]);
        cust.setLastName(param.get("lst_name")[0]);
        cust.setEmail(param.get("email")[0]);
        cust.setContact(param.get("contact")[0]);

        /* save credit card? */
        if(param.get("save_cc")[0].compareTo("yes") == 0){

            /* try save date when either month or year is dirtied */
            String strCreditCardMonth = param.get("cc_mth")[0];
            String strCreditCardYear = param.get("cc_yr")[0];
            if(strCreditCardMonth.compareTo("-1") != 0 ||
               strCreditCardYear.compareTo("-1") != 0 ){
                try{
                    cust.setCreditCardExpiry(DateFormat.parse(param.get("cc_yr")[0]
                                        + "-" + param.get("cc_mth")[0]+"-01"));
                }catch(ParseException ex){
                    m_mapErrors.put(INVALID_CC_EXPIRY, "Invalid date");
                    return false;
                }
            }
            cust.setCreditCardCVV(param.get("cc_cvv")[0]);
            cust.setCreditCardHolder(param.get("cc_hldr")[0]);
            cust.setCountry(param.get("country")[0]);
            cust.setCity(param.get("city")[0]);
            cust.setState(param.get("state")[0]);
            cust.setAddressLine1(param.get("addr_l1")[0]);
            cust.setAddressLine2(param.get("addr_l2")[0]);
            cust.setPostalCode(param.get("postal")[0]);
        }
        else{
            cust.setCreditCardNumber("");
            cust.setCreditCardCVV("");
            cust.setCreditCardType(-1);
            cust.setCreditCardHolder("");
            cust.setCreditCardExpiry(Calendar.getInstance().getTime());
            cust.setCountry("00");
            cust.setCity("");
            cust.setState("");
            cust.setAddressLine1("");
            cust.setAddressLine2("");
            cust.setPostalCode("");
        }
        return true;
    }
    /*-----------------------------------------------------------------------*/
    /* Test */
    public static void main(String[] args){

        AccountControl acctrl = new AccountControl();

        /* test getCustomer() */
        Customer cust = acctrl.getCustomer(100000);
        if(cust!=null)
            System.out.println(cust.getName() + "\t" + cust.getAddressLine1() + "\t" + cust.getCreditCardNumber());

        if(cust==null) return;

        /* test updateCustomer */
        cust.setFirstName("Hua Seng");
        cust.setCreditCardNumber("5548274033207951");
        boolean bUpdated = acctrl.updateCustomer(cust);
    }
}
